import datetime
import json
import os
import random
import re
import string
import time
from urllib.parse import unquote, urlencode

import jsonpath
import requests
from faker import Faker
from lxml import etree

from api.client import HttpClient
from common.logger import Logger
from common.read_yaml import ReadYaml_By_Root_Dict
from common.utils import Utils

fake = Faker(locale='zh_CN')
utils = Utils()
requests.packages.urllib3.disable_warnings()
env = ReadYaml_By_Root_Dict("configs/environment_var.yml").get_yaml_data()  # 读取数据
business_params = ReadYaml_By_Root_Dict("case_online/business_payload.yml").get_yaml_data()  # 读取数据
lessor_key = "id-"+''.join(random.sample(string.ascii_lowercase + string.digits, 22))

def jp(obj, expr, result_type='VALUE', debug=0, use_eval=True):
    Logger.info(f'jsonpath表达式：{expr}')
    return jsonpath.jsonpath(obj, expr, result_type='VALUE', debug=0, use_eval=True)


class MySpace(HttpClient):
    def __init__(self, session=None):
        self.session = session
        super().__init__(self.session)
        # 获取环境参数，然后得到环境参数的对应的值
        # environ = self.env_flag
        environ = "saas_myspace_test"
        self.__tenant = jp(env,f'$.{environ}.app_tenant_id')[0]
        self.__app_code = jp(env,f'$.{environ}.app_code')[0]
        self.__passport = jp(env,f'$.{environ}.business_host.passport')[0]
        self.__bms = jp(env,f'$.{environ}.business_host.bms')[0]
        self.__kfapi = jp(env,f'$.{environ}.business_host.kfapi')[0]
        self.__kefu = jp(env,f'$.{environ}.business_host.kefu')[0]
        self.users = jp(env,f'$.{environ}.users')[0] # 用户信息，字典：{user:password}
        PAYLOAD = jp(business_params, f'$.{self.env_flag}.lease_contract')[
            0]  # 从case_online/business_payload.yml文件中获取对应环境业务数据入参
        self.stage_id = jp(PAYLOAD, '$.stage_id')[0]
        self.room_id = jp(PAYLOAD, '$.fee_item[0].room_id')[0]

        self.__headers = {'sec-ch-ua': '"Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
                   'sec-ch-ua-mobile': '?0',
                   'sec-ch-ua-platform': '"Windows"',
                   'Upgrade-Insecure-Requests': '1',
                   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42',
                   'Accept': 'ajax',
                   'Content-Type': 'application/json',
                   'Sec-Fetch-Site': 'same-site'}

    # 登录
    def login_myspace(self, user, password):
        self.request = self.session
        URL = f'https://passport.test.myspacex.cn/auth/login?o=jq'
        r = self.request.get(URL, headers=self.__headers, verify=False)
        csrf = self.get_html_attr_val(r.text,'#loginForm [name="_csrf"]','value')
        data = {"_csrf":csrf,
                "tenantCode":"jq",
                "userName":"jq",
                "password":"1QAZ2wsx",
                "code":""}
        data_encode=urlencode(data) # 得到带&格式的参数
        print(f"csrf:{data_encode}")
        headers = self.__headers.copy()
        headers.update({"Content-Type":"application/x-www-form-urlencoded"})
        r = self.request.post(URL, headers=headers, data=data_encode, verify=False)

    def switch_Rental(self):
        """
        切换到租赁系统
        Returns:

        """
        URL="https://rental.test.myspacex.cn/?_smp=Rental"
        r = self.request.get(URL, headers=self.__headers, verify=False)
        print(r.status_code)

    def validate_rooms_can_rent(self,room_id, date):
        """
        查询房间租赁有效期
        Args:
            room_id: 房间id
            date: 租赁日期，起始日期一致，查询一天

        Returns:

        """
        URL = f'https://rental.test.myspacex.cn/contract/contract/validate-rooms-can-rent?_smp=Rental'
        payload = {"rooms": [
            {"room_id": room_id, "start_date": date, "end_date": date,
             "room_name": ""}], "start_date": date, "end_date": date,
                "contract_id": None}
        r = self.request.post(URL,headers=self.__headers,json=payload, verify=False)
        print(r.json())
        tips = jp(r.json(),'$.data')[0]
        return tips

    def get_can_rent_date(self, room_id, date):
        """
        获取房间可租赁的开始日期
        Args:
            room_id: 房间ID
            date: 初次查询日期

        Returns: date，可租赁开始日期

        """
        tips = self.validate_rooms_can_rent(room_id, date)
        count=0
        while tips:    # 判断返回是否有提示，如果有提示，则进入循环判断
            # 获取已租赁的期限结束日期
            end_date = re.split(r'至(\d{4}-\d{1,2}-\d{1,2})',tips[room_id])[1]
            from datetime import datetime as d1
            # 对已租赁结束期往后推一天再进行查询
            date = (d1.strptime(end_date, '%Y-%m-%d') + datetime.timedelta(days=1)).strftime("%Y-%m-%d")
            time.sleep(1)
            count += 1
            if count >=8:
                assert False, f'查询{count}次无可用日期，退出循环！'
            tips = self.validate_rooms_can_rent(room_id, date)
        return date

    def get_receivables(self,date):
        """
        获取queue_id
        Args:
            date:

        Returns:获取合同应收queue_id

        """
        URL = f"https://rental.test.myspacex.cn/contract/contract/get-receivables?t=1670654857010&_smp=Rental"
        payload = jp(business_params, f'$.{self.env_flag}.get_receivables')[0]
        utils.update_json_by_jsonpath(payload, "$.start_date", date)
        utils.update_json_by_jsonpath(payload, "$.end_date", date)
        utils.update_json_by_jsonpath(payload, "$.rent_start_date", date)
        utils.update_json_by_jsonpath(payload, "$.rent_end_date", date)
        utils.update_json_by_jsonpath(payload, "$.room_data[0].start_date", date)
        utils.update_json_by_jsonpath(payload, "$.room_data[0].end_date", date)
        utils.update_json_by_jsonpath(payload, "$.room_data[0].rent_start_date", date)
        utils.update_json_by_jsonpath(payload, "$.room_data[0].rent_end_date", date)
        utils.update_json_by_jsonpath(payload, '$.lessors[0].lessor_key', lessor_key)
        # utils.update_json_by_jsonpath(payload, '$.calc_instance_id', calc_instance_id)
        # utils.update_json_by_jsonpath(payload, '$.biz_instance_id', biz_instance_id)
        resp = self.request.post(URL, json=payload, headers=self.__headers, verify=False)
        if resp.status_code != 200:
            assert False, f"请求失败"
        elif resp.json()['msg'] != "":
            assert False, f"查询失败，{resp.json()['msg']}"
        else:
            # 合同应收queue_id
            queue_id = resp.json()['data']
            return queue_id


    def add_contract(self,contract_id,date):
        URL=f"https://rental.test.myspacex.cn/contract/contract/add?t={self.t_ms()}&_smp=Rental"
        payload = jp(business_params, f'$.{self.env_flag}.lease_contract')[
            0]  # 从case_online/business_payload.yml文件中获取对应环境业务数据入参
        cur_time = time.strftime('%Y-%m-%d %H:%M:%S')
        utils.update_json_by_jsonpath(payload, '$.contract_name', f'合同名称{cur_time}')  # 替换掉合同名称
        utils.update_json_by_jsonpath(payload, '$.contract_code', f'合同编号{cur_time}')  # 替换掉合同编号
        # 替换掉两次入参不一样的关键值
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].id', fake.uuid4())
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].contract_id', contract_id)
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].contract_room_id', fake.uuid4())
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].receiveable_id', fake.uuid4())
        utils.update_json_by_jsonpath(payload, '$.lessors[0].lessor_key', lessor_key)
        start_and_end_date = date
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].start_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.fee_item[0].data[0].receivable_list[0].end_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.start_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.end_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.rent_start_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.rent_end_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.room_data[0].start_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.room_data[0].end_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.room_data[0].rent_start_date', start_and_end_date)
        utils.update_json_by_jsonpath(payload, '$.room_data[0].rent_end_date', start_and_end_date)

        r = self.request.post(URL, headers=self.__headers, json=payload, verify=False)
        print(r.json())
        # 签订合同queue_id
        queue_id = jp(r.json(),'$.data')[0]
        return queue_id

    def get_status(self, stage_id, queue_id, type):
        """
        获取业务id
        Args:
            stage_id: 就是项目id
            queue_id: 查询ID，通过新增合同后返回
            type: 合同签订、获取合同应收

        Returns:

        """
        URL=f"https://rental.test.myspacex.cn/queue/queue/get-status?t={self.t_ms()}&_smp=Rental"
        data = {"stage_id":stage_id,"type":type,"queue_id": queue_id}
        r = self.request.post(URL, headers=self.__headers, json=data, verify=False)
        assert r.status_code==200, f'请求结果code为{r.status_code}，不为200'
        print(r.json())
        business_data = jp(r.json(),'$.data[0].business_data')[0]   # 可能获取到的是null
        count = 0
        while not business_data:
            time.sleep(1) # 等待1秒后再次请求
            r = self.request.post(URL, headers=self.__headers, json=data, verify=False)
            assert r.status_code == 200, f'请求结果code为{r.status_code}，不为200'  # 断言请求状态码为200
            business_data = jp(r.json(), '$.data[0].business_data')[0]  # 获取business_data的值
            count += 1
            if count >=5:   # 循环请求5次，否则断言失败
                assert False, f'获取业务数据business_id失败！'
        if type == '合同签订':
            business_id = business_data['id']
            return business_id
        else:
            contract_id = jp(r.json(),'$.data[0].business_data[0].fee_items[0].receivable_list[0].contract_id')[0]
            return contract_id


    def async_submit_approve(self,business_id):
        """
        通过业务单据id获取record_id，用于打开审批
        Returns:

        """
        URL=f"https://rental.test.myspacex.cn/workflow/workflow/async-commit-approval?t={self.t_ms()}&_smp=Rental"
        data = {"scene": "新签租赁合同", "business_id": business_id, "_csrf": ""}
        # data = {"scene": "新签租赁合同", "business_id": "3a0778bb-779f-04f0-d6ab-72652130c432", "_csrf": ""}
        # data = {"scene":"办理入驻","business_id":"3a077ddf-f7dc-d254-8218-0724195a8070"}
        r = self.request.post(URL, json=data, verify=False)
        print(f"async_submit_approve:{r.json()}")
        record_id = jp(r.json(),'$.data.record_id')[0]
        # record_id = ''
        return record_id

    def get_commit_info(self,record_id):
        """
        根据record_id获取审批跳转链接
        Returns:

        """
        headers = {'sec-ch-ua': '"Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
                   'sec-ch-ua-mobile': '?0',
                   'sec-ch-ua-platform': '"Windows"',
                   'Upgrade-Insecure-Requests': '1',
                   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42',
                   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                   'Sec-Fetch-Site': 'same-site'}
        URL=f"https://rental.test.myspacex.cn/workflow/workflow/get-commit-info?t={self.t_ms()}&_smp=Rental&record_id={record_id}&_csrf="
        r = self.request.get(URL, headers=headers, verify=False)
        print(f"get_commit_info:{r.json()}")
        transfer_url = jp(r.json(),'$.data.url')[0]
        print(f"transfer_url:{transfer_url}")
        # 如果跳转流程页面未发起，再重新请求获取跳转url会获取不到，需要等待1s后重新请求
        while not transfer_url:
        # if not transfer_url:
            time.sleep(1)
            r = self.request.get(URL, headers=headers, verify=False)
            print(f"get_commit_info:{r.json()}")
            transfer_url = jp(r.json(), '$.data.url')[0]
            print(f"transfer_url:{transfer_url}")
        return transfer_url

    def t_ms(self):
        """
        获取毫秒时间戳
        Returns:

        """
        t_original = time.time()
        t_ms = int(round(t_original * 1000))
        return t_ms

    # 流程中转页面
    def get_transfer_by_choice_module(self, transfer_url, module_name):
        """
        流程中转页面请求，通过模板名称获取跳转流程发起或流程审批页面地址
        Args:
            transfer_url: 流程中转url

        Returns:流程发起或者流程审批的url：/flowinstance/approval/index或/flowinstance/process/create

        """
        url = transfer_url
        r = self.request.get(url, verify=False, allow_redirects=False)
        # 判断跳转请求是否返回302，如果返回302，说明只有一个流程模板，可以通过请求头的location获取带模板id的创建url
        if r.status_code == 302:
            create_or_approve_url = r.headers['Location']
        else:
            selector = etree.HTML(r.text)
            # 通过模板名称，获取流程模板id
            module_card_element = f'//*[text()="{module_name}"]/ancestor::div[@class="layui-card"]'
            try:
                # 模板不存在或者所需属性不存在，则进行断言
                click_module_card = selector.xpath(module_card_element)[0].attrib['onclick']
            except IndexError:
                Logger.error(f'出错啦！！模板path：【{module_card_element}】不存在！！')
                assert False, f'出错啦！！模板path：【{module_card_element}】不存在！！'
            except KeyError:
                Logger.error(f'出错啦！！模板path：【{module_card_element}】中的属性【onclick】不存在！！')
                assert False, f'出错啦！！模板path：【{module_card_element}】中的属性【onclick】不存在！！'
            process_template_id = re.findall(r".*createProccess\('(.*)'", click_module_card)[0]
            # 将流程模板id与跳转URL拼接，得到发起流程带模板ID的的跳转URL
            transfer_url_module = f"{transfer_url}&process_template_id={process_template_id}"
            print(f"transfer_url_module:{transfer_url_module}")
            # 在继续请求带模板id的跳转url，得到创建流程url
            create_or_approve_url = self.get_create_url(transfer_url_module)
        return create_or_approve_url

    def get_create_url(self, url):
        """
        获取创建流程url
        Returns:

        """
        r = self.request.get(url, verify=False, allow_redirects=False)
        create_or_approve_url = r.headers['Location']
        print(f'create_url:{create_or_approve_url}')
        return create_or_approve_url

    # 启用工作流审批
    def enable_bpm_approve(self):
        url = f"{self.__bms}/m/workflow/scenario/enabled?smp=CustomerService.TaskApproveSetting&_smp=CustomerService.TaskApproveSetting"
        headers = {
            "Accept": "application/json, text/plain, */*",
            "X-YL-Tenant-Code": self.__tenant,
            "Authorization": self.Authorization,
            # "Authorization": "Bearer eyJ0eXBlIjoiSldUIiwiYWxnbyI6InNoYTI1NiIsImNyZWF0ZWRBdCI6MTY2NTgyNDc4NiwiZXhwaXJlVGltZSI6MzAwLCJyZWZyZXNoRXhwaXJlVGltZSI6NzIwMH0.eyJhY2NvdW50IjoicmV0ZXN0aW5nIiwiY29tcGFueUlEIjoiMTFiMTFkYjQtZTkwNy00ZjFmLTg4MzUtYjlkYWFiNmUxZjIzIiwibG9naW5VdWlkIjoiMjAyMjEwMTUxNDAzMTE2MzRhNGQxZmU2OTQ4IiwibW9iaWxlIjoiMTY2NjY2NjY2NjYiLCJvcGVuSWQiOiJjN2ZkZWVjY2JlMGI2YWQyNzM4NmQxMjMwYzg0NTUwODM3NWQiLCJvcmdJRCI6IjExYjExZGI0LWU5MDctNGYxZi04ODM1LWI5ZGFhYjZlMWYyMyIsIm9yZ05hbWUiOiJcdTY2N2FcdTYxNjdcdTcyNjlcdTRlMWFcdTk2YzZcdTU2ZTIiLCJvcmdOYW1lUGF0aCI6Ilx1NjY3YVx1NjE2N1x1NzI2OVx1NGUxYVx1OTZjNlx1NTZlMiIsInBvc3ROYW1lIjoiXHU2ZDRiXHU4YmQ1XHU2NTcwXHU2MzZlXHU1Yzk3XHU0ZjRkXHU1NDBkXHU3OWYwXHU2ZDRiXHU4YmQ1XHU2NTcwXHU2MzZlXHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwXHU1OTI3XHU5NTdmXHU1ZWE2XHU2ZDRiXHU4YmQ1XHU2NzAwMSIsInRlbmFudENvZGUiOiJyZXRlc3RpbmciLCJ0ZW5hbnRJRCI6IjExYjExZGI0LWU5MDctNGYxZi04ODM1LWI5ZGFhYjZlMWYyMyIsInRlbmFudE5hbWUiOiJcdTY2N2FcdTYxNjdcdTcyNjlcdTRlMWFcdTk2YzZcdTU2ZTIiLCJ1bmlvbklkIjoiODUwZGNhM2YzM2M5YmFmY2Y2MTRhNzUyYzJlZmI0OWNlNjhhIiwidXNlcklEIjoiMjJiMTFkYjQtZTkwNy00ZjFmLTg4MzUtYjlkYWFiNmUxZjIzIiwidXNlcklkIjoiMjJiMTFkYjQtZTkwNy00ZjFmLTg4MzUtYjlkYWFiNmUxZjIzIiwidXNlclR5cGUiOiJTVVBFUl9BRE1JTiIsInVzZXJuYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3NTI4XHU2MjM3In0.AV16e-mMbHFKlDeKtKKljnAO9EQzIPJjtnv7cr0hqOI",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
        }
        payload = {"id": "39ea8de6-cb5f-4999-8438-830c2cbd44e1", "enabled": 1}
        r = self.request.post(url=url, headers=headers, json=payload, verify=False)
        print(f'enable_bpm_approve:{r.json()}')

#--------------------------------------待删除代码--------------------------
    def create_process(self, create_or_approve_url):
        """
        通过创建流程url，打开流程
        Args:
            create_or_approve_url:

        Returns:

        """
        url = create_or_approve_url
        r = self.request.post(url, allow_redirects=False)
        print(r.text)

    def initiation_process(self):
        url = f'https://bpm-flow-test-new.myyscm.com/{self.__tenant}/yl/flowinstance/process/get-process-info?flow_template_id={self.flow_template_id}&package_id={self.package_id}&business_id={self.business_id}&started_organization_id=&o=retesting&_=1665889925861'
        r = self.request.get(url, verify=False)
        print(f"initiation_process:{r.json()}")

    def get_instance_id_by_task_id(self, task_id, status='审批中'):
        """
        通过task_id获取流程实例id，可以一个task可能有多次发起的流程
        Args:
            task_id: 任务ID
            status: 状态名称，中文：审批中、已作废等等。默认状态查询审批中的流程id

        Returns:对应任务id和状态的流程实例id

        """
        url = f'{self.__kefu}/{self.__tenant}/dailyservice/task-approve/list?task_id={task_id}&_smp=CustomerService.TaskRegist&pageSize=10&page=1&o={self.__tenant}&_=1666493730170'
        r = self.request.get(url, verify=False)
        print(f'get_instance_id_by_task_id:{r.json()}')
        instance_id = jp(r.json(), f"$..items[?(@.status=='{status}')].instance_id")[0]
        return instance_id

    def get_transfer_url(self, instance_id):
        url = f'{self.__kefu}/{self.__tenant}/dailyservice/task-approve/approve-detail-url?_smp=CustomerService.TaskRegist'
        payload = f'instance_id={instance_id}&o={self.__tenant}'
        header = {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
        r = self.request.post(url, data=payload, headers=header, verify=False)
        print(f'get_approve_url:{r.json()}')
        transfer_url = jp(r.json(), '$..approve_detail_url')[0]
        return transfer_url

    def business_initiate(self, user, passwd, task_name):
        myscm = self
        # myscm.login_myscm('retesting', 'retesting', 'Sh123456')
        myscm.login_myspace(user, passwd)
        myscm.enable_bpm_approve()
        task_resp = myscm.create_task(task_name)
        task_id = task_resp.json()['data']['task_ids'][0]
        myscm.cancel_task(task_id)
        # task_id = 'fa3fb912-5b21-4c85-83f7-0fc08c208586'
        transfer_url = myscm.cancel_task(task_id)
        create_url = myscm.transfer_process(transfer_url)  # 发起跳转返回给流程使用
        myscm_sess = myscm.session  # session返回给流程平台使用
        return myscm_sess, create_url, task_id

    def business_approve(self,user, passwd, record_id):
        myspace = self
        myspace.login_myspace(user, passwd)
        myspace.switch_Rental()
        myspace.enable_bpm_approve()
        record_id = myspace.async_submit_approve()
        transfer_url = myspace.get_commit_info(record_id)
        approve_url = myspace.get_transfer_by_choice_module(transfer_url, "合同新签-角色解析")
        sess = myspace.session  # session返回给流程平台使用
        return sess, approve_url



if __name__ == "__main__":
    # print(env.get(os.environ["api_test_env"]))
    myspace=MySpace()
    myspace.login_myspace('admin',1)
    myspace.switch_Rental()
    # 租期时间当前时间+1000天，开始和结束时间相同，替换所有时间
    query_date = (datetime.datetime.now() + datetime.timedelta(days=1000)).strftime("%Y-%m-%d")
    start_and_end_date = myspace.get_can_rent_date(myspace.room_id, query_date)  # 查询房间可租赁时间
    receivable_queue_id = myspace.get_receivables(start_and_end_date)
    contract_id = myspace.get_status(myspace.stage_id, receivable_queue_id, '获取合同应收')
    queue_id = myspace.add_contract(contract_id,start_and_end_date)
    business_id = myspace.get_status(myspace.stage_id,queue_id,'新签合同')
    record_id = myspace.async_submit_approve(business_id)
    transfer_url = myspace.get_commit_info(record_id)
    approve_url = myspace.get_transfer_by_choice_module(transfer_url, "合同新签-角色解析")
